/*
 * ---------------------------------------------------------------------
 * Copyright (c) 2014, 2015 All Right Reserved
 * This software is developed for study and improve coding skill ...
 *
 * Project:  Excellent Coding < EC >
 *
 * ecStack.h
 * This file for EC Stack class and interface define.
 * Eamil:  epengao@126.com
 * Author: Peter Gao
 * Version: First initinal version.
 * --------------------------------------------------------------------
 */

#ifndef EC_STACK_H
#define EC_STACK_H

#include "ecBaseType.h"

#define STACK_DEFAULT_SIZE    1024

namespace ec {

template<typename T>
class ecStack
{
public:
    ecStack();
    virtual ~ecStack();
    virtual void ResetStack();
    virtual EC_U32 Push(T* pInData);
    virtual EC_U32 Pop(T* pOutData);

protected:
    EC_U32 m_nSize;
    EC_U32 m_nItemCount;
    T*     m_pDataItems;
};

/* **************** implementation *******************/

template<typename T>
ecStack<T>::ecStack()
:m_nSize(STACK_DEFAULT_SIZE)
,m_nItemCount(0)
,m_pDataItems(EC_NULL)
{
    m_pDataItems = new T[m_nSize];
}

template<typename T>
ecStack<T>::~ecStack()
{
    if(m_pDataItems)
        delete []m_pDataItems;
}

template<typename T>
void ecStack<T>::ResetStack()
{
    m_nItemCount = 0;
}

template<typename T>
EC_U32 ecStack<T>::Push(T *pInData)
{
    if(EC_NULL == pInData)
        return EC_Err_BadParam;

    EC_U32 nRet = EC_Err_None;
    if(m_nItemCount < m_nSize)
    {
        if(m_pDataItems)
            m_pDataItems[m_nItemCount++] = *pInData;
        else
            nRet = EC_Err_Memory_Overflow;
    }
    else
    {
        T* pTmp = m_pDataItems;
        EC_U32 nNewSize = m_nSize + STACK_DEFAULT_SIZE;
        m_pDataItems = new T[nNewSize];
        if(m_pDataItems)
        {
            memcpy(m_pDataItems, pTmp, m_nSize*sizeof(T));
            m_nSize = nNewSize;
            m_pDataItems[m_nItemCount++] = *pInData;
            delete []pTmp;
        }
        else
        {
            m_pDataItems = pTmp;
            nRet = EC_Err_Memory_Overflow;
        }
    }

    return nRet;
}

template<typename T>
EC_U32 ecStack<T>::Pop(T *pOutData)
{
    if(EC_NULL == pOutData)
        return EC_Err_BadParam;

    EC_U32 nRet = EC_Err_None;
    if((m_nItemCount > 0) && m_pDataItems)
        *pOutData = m_pDataItems[--m_nItemCount];
    else
        nRet = EC_Err_DataNotExist;

    return nRet;
}
} /* namespace ec */

#endif /* EC_STACK_H */